/*
 * @Author: wuqingchun
 * @Date: 2024-06-21 09:53:04
 * @Description: httpserver 程序入口
 * @LastEditors: wuqingchun
 * @LastEditTime: 2024-10-15 14:29:58
 */

#include <getopt.h>

#include <arpa/inet.h>

#include "http.h"
#include "http_logger.h"
#include "http_poller.h"
#include "http_event.h"
#include "http_factory.h"


class CHTTPServer
{
public:
    CHTTPServer(CHTTPLogger& refLogger, HTTP_CONF_S& refConf):
        m_refLogger(refLogger),
        m_refConf(refConf),
        m_objPoller(refLogger),
        m_objConnFactory(refLogger, refConf, m_objPoller)
    {
        
    }

    int32_t Init()
    {
        int32_t iErr = m_objPoller.Init();
        if (iErr != HTTP_OK)
        {
            return iErr;
        }

        IHTTPEvent* pobjEvent = m_objConnFactory.CreateListener();
        if (pobjEvent == nullptr)
        {
            return HTTP_INII_FAIL;
        }

        iErr = m_objPoller.AddEvent(*pobjEvent, EEventType::EVENT_IN);
        if (iErr != HTTP_OK)
        {
            HTTP_ERROR(iErr, "AddEvent error");
        }
        else
        {
            HTTP_DEBUG("Init http server successfully");
        }
        
        return iErr;
    }

    int32_t Start()
    {
        m_bRun = true;

        while (m_bRun)
        {
           m_objPoller.Poll();
        }
    }

private:
    CHTTPLogger& m_refLogger;
    HTTP_CONF_S& m_refConf;
    CHTTPEventPoller m_objPoller;
    volatile bool m_bRun {false};
    CHTTPConnFactory m_objConnFactory;
};

static void __main_ShowUsage(const char* pcName, const char* pcErrMsg)
{
    if (pcErrMsg != nullptr)
    {
        printf("%s\n", pcErrMsg);
    }
    
    printf("Usage: %s -s hostname -p port\n", pcName);
    printf("\t-s --server   server hostname\n");
    printf("\t-p --port     server port\n");
    printf("\t-h --help     this help text\n");

    exit(EXIT_SUCCESS);
}

static void __main_ParseConf(int argc, char** argv, HTTP_CONF_S& refConf)
{
    char* pcHostName = nullptr;
    uint16_t usPort = 0;

    int option_index = 0;

    static struct option long_options[] = {
        {"server",     required_argument, 0, 's'},
        {"port",    required_argument, 0, 'p'},
        {"help", no_argument, 0, 'h'},
        {0,         0,                 0,  0 }
    };

    while (true)
    {
        int iCode = getopt_long(argc, argv, "hs:p:", long_options, &option_index);
        if (iCode == -1)
        {
            // 所有的命令行选项解析完成
            break;
        }

        switch (iCode)
        {
        case 'h':
        {
            __main_ShowUsage(argv[0], nullptr);
            break;
        }
        case 's':
        {
            pcHostName = optarg;
            break;
        }
        case 'p':
        {
            int32_t iPort = atoi(optarg);
            if (iPort == 0 || iPort > 65535)
            {
                __main_ShowUsage(argv[0], "Invalid server port");
            }

            usPort = iPort;

            break;
        }
        default:
            break;
        }
    }
    
    if (pcHostName == nullptr || usPort == 0)
    {
        __main_ShowUsage(argv[0], "Need server hostname and port");
    }

    if (inet_pton(AF_INET, pcHostName, &refConf.stAddr.sin_addr) != 1)
    {
        __main_ShowUsage(argv[0], "Invalid server hostname");
    }

    refConf.stAddr.sin_port = usPort;
    refConf.stAddr.sin_family = AF_INET;
}

int main(int argc, char** argv)
{
    HTTP_CONF_S stConf;
    CHTTPLogger objLogger(true, ELogLevel::LEVEL_DEBUG, 1 <<20);

    __main_ParseConf(argc, argv, stConf);

    int32_t iErr = objLogger.Init(".");
    if (iErr != HTTP_OK)
    {
        objLogger.Syslog("Logger init error, %d\n", iErr);

        return 0;
    }

    CHTTPServer objServer(objLogger, stConf);

    iErr = objServer.Init();
    if (iErr != HTTP_OK)
    {
        return 0;
    }

    objServer.Start();

    return 0;
}